<?php

namespace App\Service\Workflow;

use App\Enums\Workflow\WorkflowEnum;
use App\Models\Kms\User\KmsUser;
use App\Models\OpenShop\Common\OpenShopOrderManagerModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopAddressModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopMainProcessModel;
use App\Models\Workflow\WorkflowOrderLogModel;
use App\Models\Workflow\WorkflowOrderModel;
use App\Models\Workflow\WorkflowOrderNodeModel;
use App\Models\Workflow\WorkflowTemplateModel;
use App\Models\Workflow\WorkflowTemplateNodeModel;
use App\Service\BaseService;
use App\Service\Cruise\Mission\RenewInputService;
use App\Service\OpenShop\Feishu\OrganizationManageService;
use App\Service\Workflow\Type\RenewTypeService;
use Illuminate\Support\Facades\DB;

class WorkflowOrderService extends BaseService
{
    private WorkflowOrderModel        $workflowOrderModel;
    private ?OpenShopMainProcessModel $openShopMainProcessModel;
    private int $userId;

    public function __construct(int $id = 0, int $userId = 0)
    {
        if ($id) {
            $this->workflowOrderModel = WorkflowOrderModel::query()->find($id);
        }

        $this->userId = $userId;
    }

    public function getWorkflowOrderModel(): WorkflowOrderModel
    {
        return $this->workflowOrderModel;
    }

    /**
     * 初始化审批流
     * @param int $workflowType
     * @param int $shopId
     * @param int $relationId
     * @param int $currentUid
     * @return WorkflowOrderModel
     */
    public function init(int $workflowType, int $shopId, int $relationId = 0, int $createdByUid = 0): WorkflowOrderModel
    {
        // 校验是否可以发起审批流
        $this->verifyInit($workflowType, $shopId, $relationId);

        $templateModel = WorkflowTemplateModel::query()
                                              ->where('workflowType', $workflowType)
                                              ->where('status', WorkflowTemplateModel::STATUS_ON)
                                              ->orderByDesc('id')
                                              ->first();
        if (!$templateModel) {
            $workflowTypeText = WorkflowEnum::WORKFLOW_TYPE_TEXT[$workflowType] ?? '';
            BaseService::throwErr("未找到审批流模板:{$workflowTypeText}");
        }

        $this->openShopMainProcessModel = OpenShopMainProcessModel::query()->where('shopId', $shopId)->first();
        if (!$this->openShopMainProcessModel) {
            BaseService::throwErr("shopId:{$shopId}未匹配到开店主单");
        }

        DB::beginTransaction();

        // insert workflow_orders
        $this->workflowOrderModel               = new WorkflowOrderModel();
        $this->workflowOrderModel->workflowNo   = WorkflowOrderModel::generateWorkflowNo();
        $this->workflowOrderModel->name         = $templateModel->name;
        $this->workflowOrderModel->workflowType = $templateModel->workflowType;
        $this->workflowOrderModel->status       = WorkflowOrderModel::STATUS_ING;
        $this->workflowOrderModel->shopId       = $shopId;
        $this->workflowOrderModel->relationId   = $relationId;
        $this->workflowOrderModel->save();

        // 因为kfUid insert不进去
        $this->workflowOrderModel->createdByUid = $createdByUid;
        $this->workflowOrderModel->save();

        // insert workflow_order_nodes
        $workflowTemplateNodes = WorkflowTemplateNodeModel
            ::query()
            ->where('workflowTemplateId', $templateModel->id)
            ->get()
            ->map(function (WorkflowTemplateNodeModel $item, $k) use ($shopId, $createdByUid) {

                //  初始化自定义表单模板
                $cruiseOrderId = 0;
                if ($item->cruiseTemplateId) {
                    $renewInput = (new RenewInputService(0, 0));
                    $renewInput->initCruiseOrder($shopId, $item->cruiseTemplateId)->initOrderInput();
                    $cruiseOrderId = $renewInput->getCruiseOrderModel()->id;
                }

                // 生成handlerUid
                $handlerUid = $this->generateHandlerUid($item->handlerType, $item->handlerUid);

                // 第一个节点进行中，其余节点待处理
                if ($k == 0) {
                    $status = WorkflowOrderNodeModel::STATUS_ING;
                } else {
                    $status = WorkflowOrderNodeModel::STATUS_WAIT;
                }

                return [
                    'workflowOrderId'        => $this->workflowOrderModel->id,
                    'workflowTemplateNodeId' => $item->id,
                    'pId'                    => 0,
                    'nextId'                 => 0,
                    'prevId'                 => 0,
                    'name'                   => $item->name,
                    'status'                 => $status,
                    'businessType'           => $item->businessType,
                    'nodeType'               => $item->nodeType,
                    'handlerType'            => $item->handlerType,
                    'handlerUid'             => $handlerUid,
                    'cruiseTemplateId'       => $item->cruiseTemplateId,
                    'cruiseOrderId'          => $cruiseOrderId,
                    'condition'              => $item->condition,
                    'createdAt'              => time(),
                    'createdByUid'           => $createdByUid,
                    'updatedAt'              => time(),
                    'updatedByUid'           => 0,
                ];
            })
            ->toArray();
        WorkflowOrderNodeModel::query()->insert($workflowTemplateNodes);

        // 更新pId/nextId/prevId
        WorkflowTemplateNodeModel
            ::query()
            ->where('workflowTemplateId', $templateModel->id)
            ->get()
            ->each(function (WorkflowTemplateNodeModel $item, $k) {

                $updateArr = [];

                // 查找对应业务，在oder_nodes中的节点id
                $getOrderNodeId = function (string $column) use ($item) {
                    return WorkflowOrderNodeModel::query()
                                                 ->where('workflowOrderId', $this->workflowOrderModel->id)
                                                 ->where('workflowTemplateNodeId', $item->{$column})
                                                 ->value('id');
                };

                if ($item->pId != 0) {
                    $updateArr['pId'] = $getOrderNodeId('pId');
                }

                if ($item->nextId != 0) {
                    $updateArr['nextId'] = $getOrderNodeId('nextId');
                }

                if ($item->prevId != 0) {
                    $updateArr['prevId'] = $getOrderNodeId('prevId');
                }

                if ($updateArr) {
                    WorkflowOrderNodeModel::query()
                                          ->where('workflowOrderId', $this->workflowOrderModel->id)
                                          ->where('workflowTemplateNodeId', $item->id)
                                          ->update($updateArr);
                }
            });

        // insert 日志
        $workflowOrderNodeId = $this->workflowOrderModel->nodesRel->first()['id']; // 第一个节点id
        (new WorkflowOrderLogModel())->add($this->workflowOrderModel->id, $workflowOrderNodeId);

        DB::commit();

        return $this->workflowOrderModel;
    }

    /**
     * 生成节点处理人
     * @param int $handlerType
     * @param int $handlerUid
     * @return int
     */
    private function generateHandlerUid(int $handlerType, int $handlerUid): int
    {
        // 总部 - 指定用户
        if ($handlerType == WorkflowEnum::HANDLER_TYPE_HEAD) {
            return $handlerUid;
        }

        $mainProcessId = $this->openShopMainProcessModel->id;

        // 督导
        if ($handlerType == WorkflowEnum::HANDLER_TYPE_SUPERVISE) {
            $type = OpenShopOrderManagerModel::MANAGER_TYPE_5;
            return (int)OpenShopOrderManagerModel::getManagerUid($mainProcessId, $type);
        }

        // 省总
        if ($handlerType == WorkflowEnum::HANDLER_TYPE_PROVINCE) {
            $addressModel = OpenShopAddressModel::getData($this->openShopMainProcessModel->orderNo);
            if (!$addressModel) {
                BaseService::throwErr("{$this->openShopMainProcessModel->orderNo}未找到地址信息");
            }

            return (int)OrganizationManageService::getProvinceInfoByProvinceCode($addressModel->provinceCode)['operationUid'] ?? 0;
        }

        // 加盟商本人
        if ($handlerType == WorkflowEnum::HANDLER_TYPE_MERCHANT) {
            return (int)optional($this->openShopMainProcessModel->signOrderRel)->merchantUserId;
        }

        // 门店店长
        if ($handlerType == WorkflowEnum::HANDLER_TYPE_SHOP_MANAGER) {
            return 0; // 后面实时查询rms
        }

        return 0;
    }

    /**
     * 校验是否可以发起审批流
     * @param int $workflowType
     * @param int $shopId
     * @return void
     */
    private function verifyInit(int $workflowType, int $shopId, int $relationId): void
    {
        switch ($workflowType) {
            case WorkflowEnum::WORKFLOW_TYPE_OPEN_SHOP_RENEW:

                $order = WorkflowOrderModel
                    ::query()
                    ->where('workflowType', $workflowType)
                    ->where('shopId', $shopId)
                    ->where('status', '!=', WorkflowOrderModel::STATUS_CLOSE)
                    ->where('createdAt', '>=', time() - 86400 * 100)
                    ->first();

                if ($order) {
                    BaseService::throwErr('门店100天内，已存在续签工单，无法重复生成');
                }

                break;

            case WorkflowEnum::WORKFLOW_TYPE_SUPPLIER_TENDER:

                $order = WorkflowOrderModel
                    ::query()
                    ->where('workflowType', $workflowType)
                    ->where('relationId', $relationId)
                    ->first();

                if ($order) {
                    BaseService::throwErr('存在未完成的审批，无法重复发起');
                }

                break;
        }
    }

    /**
     * 获取当前进行中节点信息 - 可能有多个
     * 复杂节点 - 显示其子节点
     */
    public function getCurrentNodes()
    {
        return $this->workflowOrderModel->load('nodesRel')->nodesRel->where('status', WorkflowEnum::NODE_STATUS_ING)->values();
    }

    /**
     * 获取当前进行中节点信息 - 仅返回主节点
     */
    public function getCurrentMainNode()
    {
        $node = $this->workflowOrderModel->load('nodesRel')->nodesRel->where('status', WorkflowEnum::NODE_STATUS_ING)->first();
        if (!$node) {
            return null;
        }

        // 主节点
        if ($node->pId == 0) {
            return $node;
        }

        // 子节点 - 返回主节点
        return $this->workflowOrderModel->load('nodesRel')->nodesRel->where('id', $node->pId)->first();
    }

    /**
     * 获取下个节点信息 - 可能有多个
     * 复杂节点 - 显示其子节点
     */
    public function getNextNodes()
    {
        $currentNode = $this->getCurrentNodes()->first();
        if (!$currentNode) {
            BaseService::throwErr('未找到当前节点');
        }

        $nextId = $currentNode->nextId;

        // 没有下个节点
        if ($nextId == 0) {
            return null;
        }

        $nextNode = $this->workflowOrderModel->load('nodesRel')->nodesRel->where('id', $nextId)->first();
        if (!$nextNode) {
            BaseService::throwErr('未找到下个节点' . $nextId);
        }

        // 简单节点
        if (!in_array($nextNode->nodeType, WorkflowEnum::NODE_COMPLEX_TYPE)) {
            return $nextNode;
        }

        // 复杂节点
        return $nextNode->childrenRel;
    }

    /**
     * 确认处理人
     * @return $this
     */
    public function checkHandlerUid(int $uid): self
    {
        $ingNodes = $this->getCurrentNodes();

        $flag = false;
        foreach ($ingNodes as $node) {

            if ($node->handlerUid == $uid) {
                $flag = true;
                break;
            }
        }

        if (!$flag) {
            BaseService::throwErr('不是该节点的处理人:'. $node->handlerUid);
        }

        return $this;
    }

    /**
     * 完成当前节点，并切换到下个节点
     * @param int $nodeId
     * @return WorkflowOrderNodeModel|null
     */
    public function finishNodeEnterNext(
        int $nodeId,
        int $audit = 0,
        string $content = '',
        int $rejectNodeId = 0
    ): ?WorkflowOrderNodeModel {
        $ingNodes = $this->getCurrentNodes();

        $currentNode = $ingNodes->where('id', $nodeId)->first();
        if (!$currentNode) {
            BaseService::throwErr('当前节点不在进行中');
        }

        // 此节点 - 更新为完成状态
        $currentNode->status = WorkflowOrderNodeModel::STATUS_FINISH;
        if ($currentNode->handlerType == WorkflowEnum::HANDLER_TYPE_SHOP_MANAGER) {
            $currentNode->handlerUid = $this->userId;
        }
        $currentNode->save();

        if ($audit == WorkflowOrderLogModel::AUDIT_NO && $rejectNodeId) {
            $nextNodeId = $rejectNodeId;
        } else {

            // 获取下个节点
            $nextNodeId = $this->calcNextMainNodeId($currentNode, $ingNodes->toArray());
        }

        // 此节点 - 日志更新为完成状态
        // 下个节点 - 日志待处理状态
        (new WorkflowOrderLogModel())->finish($this->workflowOrderModel->id, $nodeId, $this->userId, $nextNodeId, $audit, $content,
            $rejectNodeId);

        // 没有下个节点 - 审批流结束
        if ($nextNodeId == 0) {
            $this->workflowOrderModel->status = WorkflowOrderModel::STATUS_FINISH;
            $this->workflowOrderModel->save();
            return null;
        }

        // 会签 - 还有流程没走完
        if ($nextNodeId == -1) {
            return null;
        }

        // 下个节点进入进行中
        $nextNode = WorkflowOrderNodeModel::query()->where('id', $nextNodeId)->first();
        if (!$nextNode) {
            BaseService::throwErr("未找到下个节点{$nextNodeId}");
        }

        // 下个节点的子节点
        $nextChildNodeCount = WorkflowOrderNodeModel::query()->where('pId', $nextNodeId)->count();
        if ($nextChildNodeCount) {

            // 有子节点 - 状态为等待子节点
            $nextNode->status = WorkflowOrderNodeModel::STATUS_WAIT_CHILD;
            $nextNode->save();

            // 子节点进入进行中
            WorkflowOrderNodeModel::query()->where('pId', $nextNodeId)
                                  ->update(['status' => WorkflowOrderNodeModel::STATUS_ING]);
        } else {

            // 无子节点 - 状态为进行中
            $nextNode->status = WorkflowOrderNodeModel::STATUS_ING;
            $nextNode->save();
        }

        // 驳回操作 - 把当前->驳回指定节点中的节点，全部置为待处理状态
        $currentPointer = $nodeId;
        if ($audit == WorkflowOrderLogModel::AUDIT_NO && $rejectNodeId) {
            WorkflowOrderNodeModel
                ::query()
                ->where('workflowOrderId', $this->workflowOrderModel->id)
                ->where('id', '>', $rejectNodeId)
                ->orderByDesc('id')
                ->get()
                ->each(function (WorkflowOrderNodeModel $workflowOrderNodeModel) use ($rejectNodeId, $nodeId, &$currentPointer) {

                    // 安全垫，理论上跑不到
                    if ($workflowOrderNodeModel->id == $rejectNodeId) {
                        return;
                    }

                    if ($workflowOrderNodeModel->id == $currentPointer) {
                        $workflowOrderNodeModel->status = WorkflowOrderNodeModel::STATUS_WAIT;
                        $workflowOrderNodeModel->save();

                        $currentPointer = $workflowOrderNodeModel->prevId;
                    }
                });
        }

        // 节点完成后的操作
        dispatch(function () use ($nextNode, $audit) {
            RenewTypeService::getIns($this->workflowOrderModel->workflowType, $this, $nextNode)
                            ->finishNode($audit);
        });

        return $nextNode;
    }

    // 获取下个节点
    // 如果下个节点是复杂节点，也仅返回主节点
    private function calcNextMainNodeId(WorkflowOrderNodeModel $currentNode, array $ingNodes)
    {
        // 当前在主节点
        if ($currentNode['pId'] == 0) {
            return $currentNode->nextId;
        }

        // --- 当前在子节点 ---
        $parentNode = WorkflowOrderNodeModel::query()->where('id', $currentNode['pId'])->first();
        if (!$parentNode) {
            BaseService::throwErr('未找到父节点');
        }

        // 或签 - 直接进入下一步
        if ($parentNode->nodeType == WorkflowEnum::NODE_TYPE_OR) {
            return $parentNode->nextId;
        }

        // 会签
        if ($parentNode->nodeType == WorkflowEnum::NODE_TYPE_AND) {

            // 会签所有节点都结束了
            if (count($ingNodes) <= 1) {
                return $parentNode->nextId;
            }

            // 会签还有节点未结束
            return -1;
        }

        // TODO 条件节点
        if ($parentNode->nodeType == WorkflowEnum::NODE_TYPE_IF) {
            BaseService::throwErr('条件节点的逻辑还没写');
        }

        BaseService::throwErr('未知节点类型');
    }

    /**
     * 可驳回的节点ids
     * @return array
     */
    public function rejectNodeLists(): array
    {
        $currentNode = $this->getCurrentMainNode();
        if (!$currentNode) {
            return [];
        }

        $currentNodeId = $currentNode->id;

        $rejectNodeLists = [];

        // 从后往前遍历
        WorkflowOrderNodeModel::query()
                              ->where('workflowOrderId', $this->workflowOrderModel->id)
                              ->orderByDesc('id')
                              ->get()
                              ->each(function (WorkflowOrderNodeModel $workflowOrderNodeModel) use (
                                  &$currentNodeId,
                                  &$rejectNodeLists
                              ) {
                                  if ($workflowOrderNodeModel->nextId == $currentNodeId && $workflowOrderNodeModel->pId == 0) {
                                      $rejectNodeLists[] = [
                                          'id' => $workflowOrderNodeModel->id,
                                          'name' => $workflowOrderNodeModel->name,
                                      ];

                                      $currentNodeId = $workflowOrderNodeModel->id;
                                  }

                              });


        return array_reverse($rejectNodeLists);
    }

    public function orderInfo(): array
    {
        // 订单
        $workflow      = $this->workflowOrderModel;
        $workflowClone = clone $workflow;

        // 节点
        $nodes = $this->workflowOrderModel->nodesRel;

        // 日志
        $logs = $this->workflowOrderModel->logsRel;

        // 当前节点
        $currentMainNode = $this->getCurrentMainNode();
        if ($currentMainNode) {
            $fsUser = KmsUser::query()->where('rmsUserId', $currentMainNode['handlerUid'])->first();
            $currentMainNode['handlerName'] = $fsUser->name."（{$fsUser->nickname}）";
        }

        return [
            'workflow'          => $workflowClone,
            'currentMainNode'   => $currentMainNode,
            'nodes'             => $nodes,
            'logs'              => $logs,
        ];
    }
}
